#include "widget.h"
#include "ui_widget.h"
#include<QKeyEvent>
#include<QDebug>
#include<QMessageBox>
#include<QMouseEvent>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //设置窗口透明度
    this->setWindowOpacity(0.8);
    //隐藏窗口标题栏
    this->setWindowFlag(Qt::WindowType::FramelessWindowHint);
    //设置不同种类的水果的颜色,  map<int,pair<pair<QColor,QColor>,double>>
    this->_kind = {
        {0,{{QColor(132,52,148),QColor(83,29,116)},20}},
        {1,{{QColor(199,32,32),QColor(157,39,39)},30}},
        {2,{{QColor(243,145,47),QColor(184,86,15)},40}},
        {3,{{QColor(255,240,43),QColor(197,172,30)},45}},
        {4,{{QColor(86,221,14),QColor(64,162,58)},55}},
        {5,{{QColor(255,130,126),QColor(179,101,91)},65}},
        {6,{{QColor(64,195,180),QColor(51,154,147)},75}},
        {7,{{QColor(162,162,162),QColor(93,93,93)},85}},
        {8,{{QColor(35,124,25),QColor(10,84,51)},100}},
        {9,{{QColor(10,79,131),QColor(19,26,122)},110}}
    };
    this->_painter=new QPainter();
    //QPixmap的构造函数，用给定的宽度和高度构造一个位图
    QPixmap _tempPix(_width,_height);
    //QPixmap中fill函数是用给定的颜色填充位图
    _tempPix.fill(this->_backGround);
    //在游戏区域绘制填充的颜色背景
    this->ui->lab_game->setPixmap(_tempPix);
    connection();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::connection()
{
    //信号与槽，点击Reset按钮后触发的事件
    connect(ui->btn_reset, &QPushButton::clicked, [ = ]() {
           this->_timer->stop();
           this->_fruits.clear();
           this->_score = 0.0;
           this->_timeTotal = 0.0;
           ui->lab_time->setText(QString::number(this->_timeTotal));
           ui->lab_score->setText(QString::number(this->_score));
           QPixmap tempPix(_width, _height);
           tempPix.fill(this->_backGround);
           ui->lab_game->setPixmap(tempPix);
       });
       //计时器超时发出信号
       connect(this->_timer, &QTimer::timeout, [ = ]() {
           if(isFailed()) {
               QMessageBox::information(this, "ATTENTION", "GAME OVER---(^_^)---Score : " + ui->lab_score->text());
               ui->btn_reset->click();
               return;
           }
           if(isWin()) {
               QMessageBox::information(this, "ATTENTION", "YOU WIN ---(^_^)---Score : " + ui->lab_score->text());
               ui->btn_reset->click();
               return;
           }
           //计时器的计时计算
           this->_timeTotal += this->_mse / 1000.0;
           //将时间转化成精度为2的字符显示在屏幕上
           ui->lab_time->setText(QString::number(this->_timeTotal, 'f', 2));
           if(this->_fruits.back().first.IsActive()) {
               addFruits();
           }
           dealCrash();
           this->drawFruits();
       });
       connect(ui->btn_Start, &QPushButton::clicked, [ = ]() {
           addFruits();
           this->_timer->start(this->_mse);
       });
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    //计时器正在运行且按下回车键
    if(this->_timer->isActive() && event->key() == Qt::Key_Return) {
           if(this->_fruits.back().first.IsActive()) {
               return QWidget::keyReleaseEvent(event);
           }
           this->_fruits.back().first.setActive(true);
           this->_fruits.back().first.setV_Down(100.0);
       }
       if(this->_timer->isActive() && event->key() == Qt::Key_A) {
           auto pos = this->_fruits.back().first.upDatePos() + QPointF(-12, 0);
           auto r = this->_kind[this->_fruits.back().second].second;
           if(pos.x() - r <= 0.0 || this->_fruits.back().first.IsActive()) {
               return QWidget::keyReleaseEvent(event);
           }
           this->_fruits.back().first.setPos(pos);
       }
       if(this->_timer->isActive() && event->key() == Qt::Key_D) {
           auto pos = this->_fruits.back().first.upDatePos() + QPointF(12, 0);
           auto r = this->_kind[this->_fruits.back().second].second;
           if(pos.x() + r >= this->_width || this->_fruits.back().first.IsActive()) {
               return QWidget::keyReleaseEvent(event);
           }
           this->_fruits.back().first.setPos(pos);
       }
       return QWidget::keyReleaseEvent(event);
}

void Widget::drawFruits()
{
    QPixmap tempPix(_width, _height);
       tempPix.fill(this->_backGround);
       this->_painter->begin(&tempPix);
       this->_painter->setPen(this->_redLine);
       this->_painter->drawLine(0, this->_upper_Boundary, this->_width, this->_upper_Boundary);
       for(auto &elem : this->_fruits) {
           this->_painter->setBrush(this->_kind[elem.second].first.first);
           this->_painter->setPen(QPen(QBrush(this->_kind[elem.second].first.second), 6));
           this->_painter->drawEllipse(
               elem.first.upDatePos(),
               elem.first.getR(),
               elem.first.getR());
       }
       ui->lab_game->setPixmap(tempPix);
       this->_painter->end();
}

double Widget::distanct(const QPointF &p1,const QPointF &p2)
{
     return sqrt(pow(p1.x() - p2.x(), 2) + pow(p1.y() - p2.y(), 2));
}
//处理水果碰撞
void Widget::dealCrash()
{
    auto iter1 = this->_fruits.begin();
        while (iter1 != --(--this->_fruits.end())) {
            if(iter1->first.getPos().y() - iter1->first.getR() <= this->_upper_Boundary) {
                ++iter1;
                continue;
            }
            auto tempIter = iter1;
            auto iter2 = ++tempIter;
            while(iter2 != --this->_fruits.end()) {
                //预测接下来一步会不会碰撞
                auto pos1 = iter1->first.getPos();
                auto pos2 = iter2->first.getPos();
                auto r1 = iter1->first.getR();
                auto r2 = iter2->first.getR();
                auto tempmDis = this->distanct(pos1, pos2) - (r1 + r2);
                //如果不会碰撞或还没启动，不做处理
                if(pos2.y() - r2 <= this->_upper_Boundary
                   || tempmDis > 0.1) {
                    ++iter2;
                    continue;
                }
                //得到当前的位置
                pos1 = iter1->first.getPos();
                pos2 = iter2->first.getPos();
                //得到当前的速度
                auto v1 = iter1->first.getV();
                auto v2 = iter2->first.getV();
                auto center_Vec = QPointF(pos1 - pos2);
                //将速度沿圆心连线方向投影
                auto tempPair1 = this->vectorDecomposition(v1, center_Vec);
                auto tempPair2 = this->vectorDecomposition(v2, center_Vec);
                //速度向量模的大小
                auto vecSize1 = this->module(tempPair1.first);
                auto vecSize2 = this->module(tempPair2.first);
                //如果速度过小，直接置为0.0
                if(vecSize1 <= 0.1) {
                    iter1->first.setV(QPointF(0, 0));
                    tempPair1 = {QPointF(0, 0), QPointF(0, 0)};
                }
                if(vecSize2 <= 0.1) {
                    iter2->first.setV(QPointF(0, 0));
                    tempPair2 = {QPointF(0, 0), QPointF(0, 0)};
                }
                //质量
                auto m1 = 3.14 * pow(r1, 3) * 90000;
                auto m2 = 3.14 * pow(r2, 3) * 90000;
                //碰撞模拟
                v1 = tempPair1.first;
                v2 = tempPair2.first;
                v1 = tempPair1.second + 0.4 * ((m1 - m2) * v1 + 2 * m2 * v2) / (m1 + m2);
                v2 = tempPair2.second + 0.4 * ((m2 - m1) * v2 + 2 * m1 * v1) / (m1 + m2);
                //设置碰撞后的速度
                iter1->first.setV(v1);
                iter2->first.setV(v2);
                //对越界图形进行处理
                auto change = 0.1 * center_Vec / this->module(center_Vec);
                if(pos1.y() < pos2.y()) {
                    if(r1 - r2 == 0.0) {
                        this->_score += iter2->second;
                        ui->lab_score->setText(QString::number(this->_score));
                        ++iter2->second;
                        iter2->first.setR(this->_kind[iter2->second].second);
                        iter1 = this->_fruits.erase(iter1);
                        iter2->first.setPos(pos2);
                        ++iter2;
                    } else {
                        while(this->distanct(pos1, pos2) - (r1 + r2) < 0.1) {
                            pos1 += change;
                        }
                        iter1->first.setPos(pos1);
                        iter2->first.setPos(pos2);
                        ++iter2;
                    }
                } else {
                    if(r1 - r2 == 0.0) {
                        this->_score += iter2->second;
                        ui->lab_score->setText(QString::number(this->_score));
                        ++iter1->second;
                        iter1->first.setR(this->_kind[iter1->second].second);
                        iter2 = this->_fruits.erase(iter2);
                        iter1->first.setPos(pos1);
                    } else {
                        while(this->distanct(pos1, pos2) - (r1 + r2) < 0.1) {
                            pos2 -= change;
                        }
                        iter1->first.setPos(pos1);
                        iter2->first.setPos(pos2);
                        ++iter2;
                    }
                }
            }
            ++iter1;
        }
}

void Widget::addFruits()
{
    //根据均匀离散分布产生整数随机数，P(概率)=1/b-a+1 分布区间[a,b]
    uniform_int_distribution<int> u(0, 3);
        //生成可变长度的随机整形数据
       auto kinds = u(this->_e);
       //list容器中的尾插法，将随机产生的数据存入list容器中
       this->_fruits.push_back({
           Fruit(this->_upper_Boundary,
                 this->_width, this->_height, this->_mse,
                 this->_kind[kinds].second),
           kinds
       });
}

bool Widget::isFailed()
{
    if(this->_fruits.size() <= 5) {
           return false;
       }
       auto temp = this->_fruits.begin();
       for(auto iter = this->_fruits.begin(); iter != --this->_fruits.end(); ++iter) {
           if(temp->first.getPos().y() > iter->first.getPos().y()) {
               temp = iter;
           }
       }
       if(temp->first.getPos().y() - temp->first.getR() < this->_upper_Boundary
          && temp->first.getV_Down() < 90.0) {
           return true;
       }
       return false;
}

bool Widget::isWin()
{
    auto iter = find_if(this->_fruits.begin(), this->_fruits.end(),
       [ = ](const pair<Fruit, int>& p) {
           return p.second == (--this->_kind.end())->first;
       });
       if(iter == this->_fruits.end()) {
           return false;
       }
       return true;
}

double Widget::module(const QPointF&p)
{
    return sqrt(pow(p.x(), 2) + pow(p.y(), 2));
}

pair<QPointF,QPointF>Widget::vectorDecomposition(const QPointF&source,const QPointF&target)
{
    auto a = source.x();
        auto b = source.y();
        auto c = target.x();
        auto d = target.y();
        if(c == 0.0) {
            return {
                QPointF(0, b),
                QPointF(a, 0)
            };
        }
        auto x = (a + (b * d / c)) / (1 + d * d / (c * c));
        return {
            QPointF(x, x * d / c),
            QPointF(a - x, b - x * d / c)
        };
}

void Widget::mouseMoveEvent(QMouseEvent *ev)
{
    if(this->isReleased) {
            this->curPos = ev->globalPos();
            this->isReleased = false;
            return QWidget::mouseMoveEvent(ev);
        }
        this->move(this->pos().x() + static_cast<int>((ev->globalPos().x() - this->curPos.x())),
                   this->pos().y() + static_cast<int>((ev->globalPos().y() - this->curPos.y())));
        this->curPos = ev->globalPos();
        return QWidget::mouseMoveEvent(ev);
}

void Widget::mouseReleaseEvent(QMouseEvent *ev)
{
    this->isReleased = true;
       return QWidget::mouseReleaseEvent(ev);
}


void Widget::on_btn_quit_clicked()
{
    this->close();
}
